package assignment;

import static hmm.Hmm.Smoothing.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;

import hmm.Hmm;
import hmm.Viterby;
import hmm.ViterbyResult;

/**
 * This class implements the requirements of assignment Gimel 1
 * 
 * @author Amit Yungman
 */
public class C {
  
  public static void main(String[] args) throws IOException {
    //Initialize HMM
    Hmm hmm = new Hmm( new String[]{ "corpus_for_learning.txt", 
        "corpus_for_development.txt",
        "corpus_for_evaluation.txt"},
        TYPE2);
    hmm.init();
    Viterby viterby = new Viterby(hmm);

    //Initialize sentences
    BufferedReader corpus = new BufferedReader(new FileReader("corpus_for_evaluation.txt"));
    String line = "";
    ArrayList<ArrayList<String>> sentences = new ArrayList<ArrayList<String>>();
    ArrayList<ArrayList<String>> tags = new ArrayList<ArrayList<String>>();
    ArrayList<ArrayList<String>> words = new ArrayList<ArrayList<String>>();
    ArrayList<String> currSentence = new ArrayList<String>();
    ArrayList<String> currTag = new ArrayList<String>();
    ArrayList<String> currWord = new ArrayList<String>();
    String[] word;
    for(int i = 0 ; i < 3 ; i++)
      corpus.readLine();
    while((line = corpus.readLine()) != null) {
      if(line.matches("start(\\s)*start(\\s)*start")) {
        currSentence = new ArrayList<String>();
        currTag = new ArrayList<String>();
        currWord = new ArrayList<String>();
        sentences.add(currSentence);
        tags.add(currTag);
        words.add(currWord);
        continue;
      } 
      word = line.split(" +");
      if(word.length == 3) {
        currWord.add(word[0]);
        currSentence.add(word[1]);
        currTag.add(word[2]);
      }
      else if(word.length == 2){
        currSentence.add(word[0]);
        currTag.add(word[1]);
        currWord.add("");
      } else {
        currTag.add("unknown");
        currWord.add(word[0]);
        currSentence.add(word[0]);
      }
    }
    ViterbyResult[] result3 = new ViterbyResult[sentences.size()];
    for(int i = 0 ; i < sentences.size() ; i++)
      result3[i] = viterby.calculateViterby(sentences.get(i).toArray(new String[0]));
  
    //Print the results into file
    FileWriter file3 = new FileWriter(".\\B\\3.txt");
    for(int i = 0 ; i < sentences.size() ; i++) {
      file3.write("start start start\n");
      file3.write(result3[i].p + " \n");
      for(int j = 0 ; j < sentences.get(i).size() ; j++) {
        file3.write(sentences.get(i).get(j) + " ");
        file3.write(result3[i].path[j] + " ");
        file3.write("\n");
      }
    }
    file3.flush();
    file3.close();
    
    int totalWords = 0;
    int totalErrors = 0;
    LinkedList<String> totalTags = hmm.getAllTags();
    Integer[] totalTagErrors = new Integer[totalTags.size()];
    Integer[] totalTagCount = new Integer[totalTags.size()];
    for(int i = 0 ; i < totalTagErrors.length ; i++)
      totalTagErrors[i] = totalTagCount[i] = 0;
    
    for(int i = 0 ; i < result3.length ; i++)
      for(int j = 0 ; j < result3[i].path.length ; j++) {
        String tag = tags.get(i).get(j);
        int index = totalTags.indexOf(tag);
        totalTagCount[index]++;
        totalWords++;
        if(!result3[i].path[j].equals(tag)) {
          totalTagErrors[index]++;
          totalErrors++;
        }
      }

    for(int i = 0 ; i < totalTagCount.length ; i++) {
      if(i==19)
        i=19;
      int index = getMax(i,totalTagErrors,totalTagCount);
      totalTags.add(i, totalTags.get(index));
      totalTags.add(index+1,totalTags.get(i+1));
      totalTags.remove(i+1);
      totalTags.remove(index+1);
      replaceArrayValues(totalTagCount,i,index);
      replaceArrayValues(totalTagErrors,i,index);
    }
    
    System.out.println("\nErrors by tags:");
    for(int i = 0 ; i < totalTagCount.length ; i++)
      System.out.println("\t" + totalTags.get(i) + " - " + totalTagErrors[i] + "/" + totalTagCount[i] + "  " + (totalTagCount[i] == 0 ? 0 : 100.0*totalTagErrors[i]/(totalTagCount[i])) + "%");
    System.out.println("C1:\nTotal number of errors: " + totalErrors + " over total number of words: " + totalWords);
    System.out.println("The total error precentage is " + (1.0*totalErrors / (totalWords))*100.0 + "%");
  }

  /**
   * Replaces the i-th value in the array with the j-th
   * @param array - The array
   * @param i - The first index
   * @param j - The second index
   */
  private static void replaceArrayValues(Integer[] array, int i, int j) {
    int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }

  /**
   * Returns the index of the maximal value in the division of the arrays, starting from index i
   * @param i - The beginning
   * @param array1 - The first array
   * @param array2 - The second array
   * @return The index of the maximal value
   */
  private static int getMax(int i, Integer[] array1, Integer[] array2) {
    double max = -1;
    int state = -1;
    double value;
    for(int j = i ; j < array1.length ; j++) {
      value = (array2[j] == 0) ? 0 : 1.0*array1[j]/(array2[j]);
      if(value > max) {
        max = value;
        state = j;
      }
    }
    return state;
  }
  
}
